package tasks;

import java.awt.EventQueue;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;

import main.Constants;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;


public class DownloadTask implements Taskable {

	private final String absPath;
	private final String relPath;
	private final String filename;
	private final String game;
	private final long timestamp;
	private final long size;
	private String session;
	
	private final File f;
	
	private int executeTry;

	public DownloadTask(String absPath, String relPath, String filename, 
			String game, long timestamp, long size) {
		this.absPath = absPath;
		this.relPath = relPath;
		this.filename = filename;
		this.game = game;
		this.timestamp = timestamp;
		this.size = size;
		this.executeTry = 1;
		this.f = new File(absPath+relPath+filename);
		this.session = Constants.SESSION;
	}

	@Override
	public int start(final Reportable context) {
		executeTry++;
		HttpClient client = new DefaultHttpClient();
		HttpPost post = new HttpPost(Constants.HOST_URL+"get_file.php");
		post.addHeader("Accept-Encoding","gzip,deflate");
		
		OutputStream out = null;
		try {
			//request
			List<NameValuePair> paras = new ArrayList<NameValuePair>();
			paras.add(new BasicNameValuePair("session", this.session));
			paras.add(new BasicNameValuePair("game", game));
			paras.add(new BasicNameValuePair("path", relPath));
			paras.add(new BasicNameValuePair("filename", filename));
			HttpEntity entity = new UrlEncodedFormEntity(paras, "UTF-8");
			post.setEntity(entity);
			
			//response
			HttpResponse res = client.execute(post);
			HttpEntity rEntity = res.getEntity();
			if(rEntity!=null){
				Header content = rEntity.getContentType();
				long contentLength = rEntity.getContentLength();
				if(content==null
						||!content.getValue().equals("application/octetstream")
						||contentLength<0){
					rEntity.consumeContent();
					return -1;
				}
				Header encoding = rEntity.getContentEncoding();
				InputStream in = rEntity.getContent();
				if(encoding!=null&&encoding.getValue().equals("gzip")){
					in = new GZIPInputStream(in);
				}
				//store File
				File folder = new File(absPath+relPath);
				folder.mkdirs();
				if(!f.exists()) f.createNewFile();
				out = new FileOutputStream(f);
					
				byte[] buf = new byte[4096];
				int len = 0;
				int i;
				while ((i = in.read(buf)) > 0) {
				    out.write(buf, 0, i);
				    len+=i;
				    final long process = len;
				    EventQueue.invokeLater(new Runnable(){
				    	@Override
						public void run() {
							context.reportFileProgress(game, 
					        		relPath+filename, process);
						}
				    });
				        
				    if(len>size) {
				       	rEntity.consumeContent();
				       	return -1;
				    }
				}
				out.flush();
				rEntity.consumeContent();
				if(len==size) return 0;
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {if(out!=null) 
			try{
				out.close();
				f.setLastModified(timestamp);
			}catch(Exception e1){}}
		return -1;
	}
	
	@Override
	public String toString() {
		return "[download: "+relPath+filename+"]";
	}

	@Override
	public int getTry() {
		return executeTry;
	}

	@Override
	public long getSize() {
		return size;
	}

	@Override
	public String getPath() {
		return relPath+filename;
	}

}
